home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Storage / Bento / EmbedHdr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  15.0 KB  |  529 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        EmbedHdr.cpp
  3.  
  4.     Contains:    Class definition for ODEmbeddedHandlers class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     1/15/96    TJ        Cleaned Up
  13.          <8>    10/24/95    jpa        1293441: Bento memory reserve & fatal
  14.                                     container err.
  15.          <7>     5/26/95    VL        1251403: Multithreading naming support.
  16.          <6>     5/11/95    EL        1245113: fix bug of writing out garbage
  17.                                     with buffering.
  18.          <5>      4/7/95    EL        1213321: Use a different buffering scheme.
  19.          <4>    11/14/94    VL        1188257: Use Bento errors in BenotDef.h.
  20.          <3>     8/26/94    EL        #1182275 Allows writing embeded value in
  21.                                     large block to decrease fragmentation.
  22.                                     #1182308 Allows non-byte swapping
  23.                                     format/extract
  24.          <2>     6/18/94    MB        Correct memory includes
  25.          <1>     5/27/94    VL        first checked in
  26.  
  27.         
  28. */
  29.  
  30. #ifndef    _ODTYPES_
  31. #include "ODTypes.h"
  32. #endif
  33.  
  34. #ifndef _BENTOHDR_
  35. #include "BentoHdr.h"
  36. #endif
  37.  
  38. #ifndef _EMBEDHDR_
  39. #include "EmbedHdr.h"
  40. #endif
  41.  
  42. #ifndef _SESSHDR_
  43. #include "SessHdr.h"
  44. #endif
  45.  
  46. #ifndef _INDHDR_
  47. #include "IndHdr.h"
  48. #endif
  49.  
  50. #ifndef _EXCEPT_
  51. #include "Except.h"
  52. #endif
  53.  
  54. #ifndef _FLIPEND_
  55. #include "FlipEnd.h"
  56. #endif
  57.  
  58. #ifndef __CM_API__
  59. #include "CMAPI.h"
  60. #endif
  61.  
  62. #ifndef _ODMEMORY_
  63. #include "ODMemory.h"
  64. #endif
  65.  
  66. #ifndef _ERRORDEF_
  67. #include "ErrorDef.xh"
  68. #endif
  69.  
  70. #ifndef __STRING__
  71. #include "string.h"        // For strcpy and strcmp
  72. #endif
  73.  
  74. #ifndef _BENTODEF_
  75. #include "BentoDef.h"
  76. #endif
  77.  
  78. #ifndef _SESSHDR_
  79. #include "SessHdr.h"
  80. #endif
  81.  
  82. //==============================================================================
  83. // Scalar Types
  84. //==============================================================================
  85.  
  86. struct ContainerLabelFmt {            /* Layout of a container label:            */
  87.  ODUByte magicBytes[8];                /* 8 bytes: the magic byte identifier    */
  88.  ODUShort flags;                    /* 2    the label flag                    */
  89.  ODUShort bufSize;                    /* 2    TOC buffer size / 1024            */
  90.  ODUShort majorVersion;                /* 2    major format version number        */
  91.  ODUShort minorVersion;                /* 2    minor format version number        */
  92.  ODULong tocOffset;                    /* 4    offset to start of TOC            */
  93.  ODULong tocSize;                    /* 4    total byte size of the TOC        */
  94. };
  95. typedef struct ContainerLabelFmt ContainerLabelFmt;
  96.  
  97.  
  98. #pragma segment EmbedHdr
  99.  
  100. static void ODFlipMove(ODPtr from, ODPtr to, ODULong size)
  101. {
  102.     char    *dest = (char *)to + size - 1;
  103.     char    *src = (char *)from;
  104.     
  105.     while (size--)
  106.         *dest-- = *src++;            
  107. }
  108.  
  109. //==============================================================================
  110. // ODEmbeddedHandlers
  111. //==============================================================================
  112.  
  113. ODEmbeddedHandlers::ODEmbeddedHandlers(CMSession session, CMValue parentValue)
  114. {
  115.     fParentValue = parentValue;
  116.     fSession = session;
  117. }
  118.  
  119. ODEmbeddedHandlers::~ODEmbeddedHandlers()
  120. {
  121. }
  122.  
  123. void ODEmbeddedHandlers::Initialize()
  124. {
  125.     ODSByte    typeName[kBentoTypeNameSize];
  126.     
  127.     CMContainer    container   = CMGetValueContainer(fParentValue);
  128.     CMSession    sessionData = CMGetSession(container);
  129.     
  130.     if (sessionData != fSession)
  131.         THROW(kODErrBentoErr);
  132.  
  133.     ODSessionMustHaveCMAllocReserve(container);
  134.     
  135.     CMSetMetaHandler(fSession, kODEmbeddedContainerTypeName, (CMMetaHandler) containerMetahandler);
  136.     
  137.     CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, typeName, kODNULL);
  138.     
  139.     fReverseEndian = 0;                        /* assume same endian-ness            */
  140.     fPosition    = 0;                        /* container not "open" yet            */
  141.     fSize    = 0;                            /* don't know size yet                */
  142. #if kLargeEmbeddedBlock
  143.     fBufferBegin = 0;
  144.     fBuffer = kODNULL;
  145. #endif
  146.     strcpy(fTypeName, typeName);            /* copy in the container typeName    */
  147.  
  148.     ODSessionRestoreCMAllocReserve(container);
  149. }
  150.  
  151. CMSession ODEmbeddedHandlers::GetCMSession()
  152. {
  153.     return fSession;
  154. }
  155.  
  156. CMRefCon ODEmbeddedHandlers::OpenHandler(CMOpenMode mode)
  157. {
  158.     /* Get the size of the value.  For writing it better be 0 and for reading non-zero...    */
  159.     
  160.     fSize = (ODULong) CMGetValueSize(fParentValue);
  161. #if kLargeEmbeddedBlock
  162.     fBufferBegin = fSize;
  163.     fBuffer = (ODSByte *)ODNewPtr(kEmbeddedBlockSize);
  164. #endif    
  165.     /* Check the open mode and do appropriate checks on size. Set appropriate position...    */
  166.     
  167.     if (strcmp((ODSByte*) mode, "wb+") == 0) {                /* writing...    */
  168.         if (fSize != 0) {                                    /* size must be zero    */
  169.             CMError(fSession, "Cannot create embedded container (type \"^0\") for a value that already has data!", fTypeName);
  170.             return (kODNULL);
  171.         }
  172.         fPosition = 0;                                    /* position to 1st free byte    */
  173.     } else if (strcmp((ODSByte*) mode, "rb") == 0) {         /* reading...                    */
  174.         if (fSize == 0) {                                    /* size must be non-zero        */
  175.             CMError(fSession, "Cannot read embedded container (type \"^0\") for a value that doesn't have data!", fTypeName);
  176.             return (kODNULL);
  177.         }
  178.         fPosition = 0;                                    /* position to 1st byte to read            */
  179.     } else if (strcmp((char *)mode, "rb+") == 0)              /* converting or updating...            */
  180.         fPosition = fSize;                                /* size can be anything(position at end)*/
  181.     else {                                                                                /* bad mode...                                                    */
  182.         CMError(fSession, "Invalid embedded container (type \"^0\") open mode (\"^1\")!", fTypeName, (char *)mode);
  183.         return (kODNULL);
  184.     }
  185.     
  186.     return ((CMRefCon) this);
  187. }
  188.  
  189. void ODEmbeddedHandlers::CloseHandler()
  190. {
  191. #if kLargeEmbeddedBlock
  192.     if (fBuffer != kODNULL) {
  193.         (void) this->FlushHandler();
  194.         ODDisposePtr(fBuffer);
  195.         fBuffer = kODNULL;
  196.     }
  197. #endif
  198. }
  199.  
  200. CMSize ODEmbeddedHandlers::FlushHandler()
  201. {
  202. #if kLargeEmbeddedBlock
  203.     /* write out the data in the buffer */
  204.     if (fBufferBegin != fSize) {
  205.         CMWriteValueData(fParentValue, fBuffer, fBufferBegin, (CMSize) (fSize - fBufferBegin));
  206.         fBufferBegin = fSize;
  207.     }
  208. #endif
  209.     return ((CMSize) 0);
  210. }
  211.  
  212. CMSize ODEmbeddedHandlers::SeekHandler(CM_LONG posOff, CMSeekMode mode)
  213. {
  214.     if (mode == kCMSeekSet)
  215.         fPosition = (ODULong) posOff;
  216.     else if (mode == kCMSeekEnd)
  217.         fPosition = (ODSLong) fSize + posOff;
  218.     else
  219.         fPosition = (ODSLong) fPosition + posOff;
  220.             
  221.     return 0;
  222. }
  223.  
  224. CMSize ODEmbeddedHandlers::TellHandler()
  225. {    
  226.     return fPosition;
  227. }
  228.  
  229. CMSize ODEmbeddedHandlers::ReadHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  230. {
  231.     ODULong    tryToRead = (ODULong) elementSize * (ODULong) theCount;
  232.  
  233. #if kLargeEmbeddedBlock
  234.     ODULong    amountRead = 0;
  235.     
  236.     if (fPosition < fBufferBegin) {
  237.         /* at least some of it on disk */
  238.         if (tryToRead > (fBufferBegin - fPosition)) {
  239.             /* first read from disk, later read from buffer */
  240.             amountRead = (ODULong) CMReadValueData(fParentValue, buffer, fPosition, 
  241.                                                       (CMSize) (fBufferBegin - fPosition));
  242.             if (amountRead != (fBufferBegin - fPosition)) {
  243.                 /* trouble, don't continue */
  244.                 fPosition += amountRead;            /* update position by amount read                */
  245.                 
  246.                 tryToRead = 0;        
  247.             }
  248.             else {
  249.                 fPosition += amountRead;            /* update position by amount read                */
  250.                 tryToRead -= amountRead;
  251.                 buffer = (CMPtr)((char *)buffer + amountRead);
  252.             }
  253.         }
  254.         else { /* it should all be from disk */
  255.             amountRead = (ODULong) CMReadValueData(fParentValue, buffer, fPosition, 
  256.                                                       (CMSize) tryToRead);
  257.             fPosition += amountRead;            /* update position by amount read                */
  258.             
  259.             return ((CMSize) amountRead);        
  260.         }
  261.     }
  262.  
  263.     if ((tryToRead) && (fPosition >= fBufferBegin)) {                /* it may be in the buffer                */
  264.         if (tryToRead > (fSize - fPosition))
  265.             tryToRead = fSize - fPosition;
  266.         ODBlockMove(fBuffer+fPosition-fBufferBegin, buffer, tryToRead);
  267.         amountRead += tryToRead;
  268.         fPosition += tryToRead;
  269.     }
  270.     
  271.     return ((CMSize) amountRead);        
  272.     
  273. #else
  274.     tryToRead = (ODULong) CMReadValueData(fParentValue,     
  275.                                             buffer,
  276.                                             fPosition, 
  277.                                             (CMSize) tryToRead);
  278.     
  279.     fPosition += tryToRead;                        /* update position by amount read                */
  280.     
  281.     return ((CMSize) tryToRead);        
  282. #endif
  283. }
  284.  
  285. CMSize ODEmbeddedHandlers::WriteHandler(CMPtr buffer, CMSize elementSize, CMCount theCount)
  286. {
  287.     ODULong tryWriteAmount = (ODULong) elementSize * (ODULong) theCount;
  288. #if kLargeEmbeddedBlock
  289.     ODULong amountWritten = 0;
  290.     
  291.     /* if there is any data in the portion that is already on disk, write those out first */
  292.     if (fPosition < fBufferBegin) {
  293.         if ((fPosition + tryWriteAmount) > fBufferBegin) { /* it goes over to the buffer */
  294.             amountWritten = fBufferBegin - fPosition;
  295.             tryWriteAmount -= amountWritten;
  296.         }
  297.         else {
  298.             amountWritten = tryWriteAmount;
  299.             tryWriteAmount = 0;
  300.         }
  301.         CMWriteValueData(fParentValue, buffer, fPosition, amountWritten);
  302.         fPosition += amountWritten;
  303.         buffer = (CMPtr)((char *)buffer + amountWritten);
  304.     }
  305.     
  306.     /* if there is any that should go into the buffer or extend to the buffer, move them there */
  307.     
  308.     while (tryWriteAmount > 0) {
  309.         if ((fPosition + tryWriteAmount) <= (fBufferBegin + kEmbeddedBlockSize)) {
  310.             /* we can put everything into the buffer                                        */
  311.             ODBlockMove(buffer, fBuffer + fPosition - fBufferBegin, tryWriteAmount);
  312.             amountWritten += tryWriteAmount;
  313.             fPosition += tryWriteAmount;
  314.             if (fPosition > fSize)
  315.                 fSize = fPosition;
  316.             tryWriteAmount = 0;        /* so we are done */            
  317.         }
  318.         else {
  319.             /* we go beyond the end of the buffer, so we cannot put there directly */
  320.             if (fBufferBegin < fSize) {
  321.                 /* if there are data in the buffer, flush it first, maybe there is room afterwards */
  322.                 (void) this->FlushHandler();
  323.             }
  324.             else {
  325.                 /* there is no data in buffer, yet it does not fit, so just write it out directly */
  326.                 CMWriteValueData(fParentValue, buffer, fPosition, (CMSize) tryWriteAmount);
  327.                 amountWritten += tryWriteAmount;
  328.                 fPosition += tryWriteAmount;
  329.                 fSize = fPosition;
  330.                 fBufferBegin = fSize;
  331.                 tryWriteAmount = 0;        /* so we are done */            
  332.             }
  333.         }
  334.     }
  335.     return amountWritten;
  336. #else
  337.     CMWriteValueData(fParentValue, buffer, fPosition, (CMSize) tryWriteAmount);
  338.     fPosition += tryWriteAmount;                    /* update position by amount written    */
  339.  
  340.     if (fPosition > fSize)                        /* if writing past end of value...        */
  341.         fSize = fPosition;                        /* ...set new value size                */
  342.     
  343.     return tryWriteAmount;
  344. #endif
  345.     
  346. }
  347.  
  348. CMEofStatus ODEmbeddedHandlers::EOFHandler()
  349. {
  350.     return ((CMEofStatus) kODFalse);
  351. }
  352.  
  353. CMBoolean ODEmbeddedHandlers::TruncHandler(CMSize containerSize)
  354. {
  355.     if ((ODULong)containerSize <= fSize) {
  356. #if kLargeEmbeddedBlock
  357.         /* only need actually to delete if end result is nothing in the buffer */
  358.         if ((ODULong)containerSize <= fBufferBegin) {
  359.             ODULong    amountToDelete;
  360.             if (fSize > fBufferBegin)
  361.                 amountToDelete = fBufferBegin - (ODULong) containerSize;        /* don't delete amount in buffer */
  362.             else
  363.                 amountToDelete = fSize - (ODULong) containerSize;            /* else delete from end */
  364.             CMDeleteValueData(fParentValue,  (CMCount) containerSize, (CMSize) amountToDelete);
  365.             fBufferBegin = (ODULong) containerSize;        /* so it would match fSize => empty buffer */
  366.         }
  367. #else
  368.     CMDeleteValueData(fParentValue,                                         
  369.                         (CMCount) containerSize,
  370.                         (CMSize) (fSize - (ODULong) containerSize));
  371. #endif
  372.         fSize    = (ODULong) containerSize;    
  373.     
  374.         return kODTrue;
  375.     }
  376.     else
  377.         return kODFalse;
  378. }
  379.  
  380. CMSize ODEmbeddedHandlers::ContainerSizeHandler()
  381. {
  382.     fPosition = fSize;                        /* moral equivalent of seek/tell    */
  383.     
  384.     return ((CMSize) fSize);
  385. }
  386.  
  387. void ODEmbeddedHandlers::ReadLabelHandler(CMMagicBytes magicByteSequence,
  388.                                      CMContainerFlags *flags, CM_USHORT *bufSize,
  389.                                      CM_USHORT *majorVersion, CM_USHORT *minorVersion,
  390.                                      CMSize *tocOffset, CMSize *tocSize)
  391. {
  392.     ODULong            labelSize;
  393.     ContainerLabelFmt    theLabel;
  394.  
  395.     /* Seek to the end of the label at the end of the value and read it...                                */
  396.     
  397.     this->SeekHandler(-(ODSLong)sizeof(ContainerLabelFmt), kCMSeekEnd);
  398.     labelSize = (ODULong) this->ReadHandler((CMPtr) &theLabel,
  399.                                                 (CMSize) sizeof(ODUByte),
  400.                                                 (CMCount) sizeof(ContainerLabelFmt));
  401.     
  402.     if (labelSize != sizeof(ContainerLabelFmt)) {        /* must have read it all!                            */
  403.         CMError(fSession, "Embedded container (type \"^0\") label could not be read!", fTypeName);
  404.         return;
  405.     }
  406.     
  407.     /* Return all the label info...                                                                                                                */
  408.     
  409.     ODBlockMove(theLabel.magicBytes, magicByteSequence, 8);
  410. #if kCMDefaultEndian
  411.     /* little endian machine */
  412.     if ((theLabel.flags & kCMLittleEndianTwin) == 0) {
  413. #else
  414.     /* big endian machine */
  415.     if (theLabel.flags & kCMLittleEndianTwin) {
  416. #endif
  417.         fReverseEndian = kODTrue;
  418.         *flags = ODFlipShort(theLabel.flags);
  419.         *bufSize = ODFlipShort(theLabel.bufSize);
  420.         *majorVersion = ODFlipShort(theLabel.majorVersion);
  421.         *minorVersion = ODFlipShort(theLabel.minorVersion);
  422.         *tocOffset = ODFlipLong(theLabel.tocOffset);
  423.         *tocSize = ODFlipLong(theLabel.tocSize);
  424.     }
  425.     else {
  426.         *flags = (CMContainerFlags)theLabel.flags;
  427.         *bufSize = (CM_USHORT)theLabel.bufSize;
  428.         *majorVersion = (CM_USHORT)theLabel.majorVersion;
  429.         *minorVersion = (CM_USHORT)theLabel.minorVersion;
  430.         *tocOffset = (CMSize)theLabel.tocOffset;
  431.         *tocSize = (CMSize)theLabel.tocSize;
  432.     }
  433. }
  434.  
  435. void ODEmbeddedHandlers::WriteLabelHandler(CMMagicBytes magicByteSequence,
  436.                                         CMContainerFlags flags, CM_USHORT bufSize,
  437.                                         CM_USHORT majorVersion, CM_USHORT minorVersion,
  438.                                         CMSize tocOffset, CMSize tocSize)
  439. {
  440.     ODULong            labelSize;
  441.     ContainerLabelFmt    theLabel;
  442.  
  443.     /* Fill in the label buffer with the info...                                                                                    */
  444.     
  445.     flags = (CMContainerFlags) ((CM_USHORT)flags & ~kCMLittleEndianTwin);    /* ignore what is passed in */
  446.     if (fReverseEndian) {
  447.         theLabel.flags = ODFlipShort(flags | (kCMLittleEndianTwin & ~kCMDefaultEndian));
  448.         theLabel.bufSize = ODFlipShort(bufSize);
  449.         theLabel.majorVersion = ODFlipShort(majorVersion); 
  450.         theLabel.minorVersion = ODFlipShort(minorVersion);
  451.         theLabel.tocOffset = ODFlipLong(tocOffset);
  452.         theLabel.tocSize = ODFlipLong(tocSize);
  453.     }
  454.     else {
  455.         theLabel.flags = (ODUShort)(flags | kCMDefaultEndian);
  456.         theLabel.bufSize = (ODUShort)bufSize;
  457.         theLabel.majorVersion = (ODUShort)majorVersion; 
  458.         theLabel.minorVersion = (ODUShort)minorVersion;
  459.         theLabel.tocOffset = (ODULong)tocOffset;
  460.         theLabel.tocSize = (ODULong)tocSize;
  461.     }
  462.     
  463.     ODBlockMove(magicByteSequence, theLabel.magicBytes, 8);
  464.  
  465.     /* Write the label to the end of the embedded container value...*/
  466.     
  467.     this->SeekHandler(0, kCMSeekEnd);
  468.     labelSize = (ODULong) this->WriteHandler((CMPtr) &theLabel,
  469.                                             (CMSize) sizeof(unsigned char),
  470.                                             (CMCount) sizeof(ContainerLabelFmt));
  471.  
  472.     if (labelSize != sizeof(ContainerLabelFmt))
  473.         THROW(kODErrBentoErr);
  474. }
  475.  
  476. CMValue ODEmbeddedHandlers::ReturnParentValueHandler()
  477. {
  478.     return fParentValue;
  479. }
  480.  
  481. CM_UCHAR* ODEmbeddedHandlers::ReturnContainerNameHandler()
  482. {
  483.     return ((CM_UCHAR *) fTypeName);
  484. }
  485.  
  486. CMType ODEmbeddedHandlers::ReturnTargetTypeHandler(CMContainer container)
  487. {
  488.     CMType indirectType;
  489.     
  490.     CMSetMetaHandler(fSession,
  491.                     kODIndirectValueGlobalName,
  492.                     IndirectDynamicValueMetahandler);
  493.     indirectType = CMRegisterType(container, kODIndirectValueGlobalName);
  494.                         
  495.     return indirectType;
  496. }
  497.  
  498. void ODEmbeddedHandlers::ExtractDataHandler(CMDataBuffer buffer,
  499.                                                  CMSize size, CMPrivateData data)
  500. {
  501.     ODBoolean    reverseEndian = fReverseEndian;
  502.     
  503.     if ((long)size < 0) {    /* this means it is endian-ness netural    */
  504.         size = -(long)size;
  505.         reverseEndian = kODFalse;
  506.     }
  507.     
  508.     if (reverseEndian)
  509.         ODFlipMove(buffer, data, (size_t)size);
  510.     else
  511.         ODBlockMove(buffer, data, (size_t)size);
  512. }
  513.  
  514. void ODEmbeddedHandlers::FormatDataHandler(CMDataBuffer buffer,
  515.                                      CMSize size, CMPrivateData data)
  516. {
  517.     ODBoolean    reverseEndian = fReverseEndian;
  518.     
  519.     if ((long)size < 0) {    /* this means it is endian-ness netural    */
  520.         size = -(long)size;
  521.         reverseEndian = kODFalse;
  522.     }
  523.     
  524.     if (reverseEndian)
  525.         ODFlipMove(data, buffer, (size_t)size);
  526.     else
  527.         ODBlockMove(data, buffer, (size_t)size);
  528. }
  529.